package org.chen.scene.service.task.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.chen.common.scene.dto.AttractionQueryDTO;
import org.chen.common.scene.task.AttractionResult;
import org.chen.common.scene.task.GrabTask;
import org.chen.common.scene.task.GrabTaskLog;
import org.chen.scene.mapper.GrabTaskMapper;
import org.chen.scene.service.AttractionService;
import org.chen.scene.service.task.GrabTaskLogService;
import org.chen.scene.service.task.GrabTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.*;

@Service
@Slf4j
public class GrabTaskServiceImpl extends ServiceImpl<GrabTaskMapper, GrabTask> implements GrabTaskService {
    @Autowired
    private GrabTaskMapper grabTaskMapper;

    @Autowired
    private AttractionService attractionService;

    @Autowired
    private GrabTaskLogService grabTaskLogService;

    // 创建单线程执行器，确保任务串行执行
    private final ExecutorService taskExecutor = Executors.newSingleThreadExecutor(r -> {
        Thread thread = new Thread(r, "grab-task-executor");
        thread.setDaemon(true);
        return thread;
    });

    // 随机数生成器，用于生成随机延迟
    private final Random random = new Random();

    @Override
    public List<GrabTask> getAllTask() {
        return grabTaskMapper.selectList(new QueryWrapper<>());
    }

    @Override
    public void addGrabTask(GrabTask task) {
        try {
            task.setCreateTime(LocalDateTime.now());
            task.setUpdateTime(LocalDateTime.now());
            grabTaskMapper.insert(task);
            log.info("创建任务: {} - {}", task.getCityName(), task.getKeywords());
        } catch (Exception e) {
            log.error("创建任务失败: {}", task.getCityName(), e);
            throw new RuntimeException("创建任务失败: " + e.getMessage());
        }
    }

    @Override
    public GrabTask updateGrabTask(GrabTask task) {
        try {
            // 1. 检查任务是否存在
            GrabTask existingTask = grabTaskMapper.selectById(task.getId());
            if (existingTask == null) {
                throw new RuntimeException("任务不存在: " + task.getId());
            }

            // 可修改的字段
            existingTask.setStartPageIndex(task.getStartPageIndex());
            existingTask.setEndPageIndex(task.getEndPageIndex());
            existingTask.setPageSize(task.getPageSize());
            existingTask.setKeywords(task.getKeywords());
            existingTask.setCityName(task.getCityName());
            existingTask.setUpdateTime(LocalDateTime.now());

            grabTaskMapper.updateById(existingTask);
            return existingTask;

        } catch (Exception e) {
            log.error("更新定时任务失败: {}", task.getId(), e);
            throw new RuntimeException("更新定时任务失败: " + e.getMessage());
        }
    }

    @Override
    public void deleteGrabTask(Long id) {
        try {
            // 从数据库删除
            grabTaskMapper.deleteById(id);
            log.info("删除任务: {}", id);

        } catch (Exception e) {
            log.error("删除任务失败: {}", id, e);
            throw new RuntimeException("删除任务失败: " + e.getMessage());
        }
    }

    /**
     * 执行抓取任务（带延迟控制和日志记录）
     */
    public void executeGrabTaskNow(Long id) {
        // 从数据库获取最新的任务信息
        GrabTask taskEntity = grabTaskMapper.selectById(id);
        if (taskEntity == null) {
            log.warn("任务不存在: {}", id);
            return;
        }

        log.info("立即执行任务: {} - {}", taskEntity.getCityName(), taskEntity.getKeywords());

        if (taskEntity.getEndPageIndex() != null) {
            // 多页抓取，添加延迟控制
            executeMultiPageTask(taskEntity);
        } else {
            // 单页抓取
            executeSinglePageTask(taskEntity);
        }

        // 更新任务统计信息
        updateTaskStatistics(taskEntity.getId());
    }

    /**
     * 执行多页任务（带延迟和日志）
     */
    private void executeMultiPageTask(GrabTask taskEntity) {
        int totalPages = taskEntity.getEndPageIndex();
        log.info("开始执行多页任务，总页数: {}", totalPages);

        for (int i = 1; i <= totalPages; i++) {
            GrabTaskLog taskLog = null;
            try {
                // 创建执行日志
                taskLog = grabTaskLogService.createLog(
                        taskEntity.getId(),
                        taskEntity.getCityName(),
                        taskEntity.getKeywords(),
                        i,
                        taskEntity.getPageSize()
                );

                AttractionQueryDTO attractionQueryDTO = new AttractionQueryDTO();
                attractionQueryDTO.setCityName(taskEntity.getCityName());
                attractionQueryDTO.setCount(taskEntity.getPageSize());
                attractionQueryDTO.setIndex(i);
                attractionQueryDTO.setKeyword(taskEntity.getKeywords());
                attractionQueryDTO.setSortType(1);

                log.info("正在抓取第 {}/{} 页", i, totalPages);

                // 执行抓取并获取统计结果 - 修改这里
                AttractionResult result = attractionService.getAttractionsWithResult(attractionQueryDTO);

                // 更新执行日志
                grabTaskLogService.updateLogResult(
                        taskLog.getId(),
                        result.getTotalCount(),
                        result.getNewCount(),
                        result.getUpdateCount(),
                        "SUCCESS",
                        null
                );

                log.info("第 {} 页抓取完成，总数: {}, 新增: {}, 更新: {}",
                        i, result.getTotalCount(), result.getNewCount(), result.getUpdateCount());

                // 除了最后一页，其他页面抓取后都要延迟
                if (i < totalPages) {
                    long delay = getRandomDelay();
                    log.info("第 {} 页抓取完成，等待 {} 毫秒后继续...", i, delay);
                    Thread.sleep(delay);
                }

            } catch (InterruptedException e) {
                log.warn("任务被中断: {}", e.getMessage());
                if (taskLog != null) {
                    grabTaskLogService.updateLogResult(taskLog.getId(), 0, 0, 0, "FAILED", "任务被中断");
                }
                Thread.currentThread().interrupt();
                break;
            } catch (Exception e) {
                log.error("抓取第 {} 页时发生错误: {}", i, e.getMessage(), e);
                if (taskLog != null) {
                    grabTaskLogService.updateLogResult(taskLog.getId(), 0, 0, 0, "FAILED", e.getMessage());
                }
                // 发生错误时也要延迟，避免频繁重试
                try {
                    Thread.sleep(getRandomDelay() * 2); // 错误时延迟更久
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }

        log.info("多页任务执行完成: {} - {}", taskEntity.getCityName(), taskEntity.getKeywords());
    }

    /**
     * 执行单页任务（带日志）
     */
    private void executeSinglePageTask(GrabTask taskEntity) {
        GrabTaskLog taskLog = null;
        try {
            // 创建执行日志
            taskLog = grabTaskLogService.createLog(
                    taskEntity.getId(),
                    taskEntity.getCityName(),
                    taskEntity.getKeywords(),
                    taskEntity.getStartPageIndex(),
                    taskEntity.getPageSize()
            );

            AttractionQueryDTO attractionQueryDTO = new AttractionQueryDTO();
            attractionQueryDTO.setCityName(taskEntity.getCityName());
            attractionQueryDTO.setCount(taskEntity.getPageSize());
            attractionQueryDTO.setIndex(taskEntity.getStartPageIndex());
            attractionQueryDTO.setKeyword(taskEntity.getKeywords());
            attractionQueryDTO.setSortType(1);

            log.info("执行单页任务，页码: {}", taskEntity.getStartPageIndex());

            // 执行抓取并获取统计结果 - 修改这里
            AttractionResult result = attractionService.getAttractionsWithResult(attractionQueryDTO);

            // 更新执行日志
            grabTaskLogService.updateLogResult(
                    taskLog.getId(),
                    result.getTotalCount(),
                    result.getNewCount(),
                    result.getUpdateCount(),
                    "SUCCESS",
                    null
            );

            log.info("单页任务执行完成: {} - {}，总数: {}, 新增: {}, 更新: {}",
                    taskEntity.getCityName(), taskEntity.getKeywords(),
                    result.getTotalCount(), result.getNewCount(), result.getUpdateCount());

        } catch (Exception e) {
            log.error("执行单页任务时发生错误: {}", e.getMessage(), e);
            if (taskLog != null) {
                grabTaskLogService.updateLogResult(taskLog.getId(), 0, 0, 0, "FAILED", e.getMessage());
            }
        }
    }

    /**
     * 更新任务统计信息
     */
    private void updateTaskStatistics(Long taskId) {
        try {
            Map<String, Object> stats = grabTaskLogService.getTaskExecuteStats(taskId);

            GrabTask task = grabTaskMapper.selectById(taskId);
            if (task != null) {
                task.setTotalExecuteCount(((Number) stats.getOrDefault("executeCount", 0)).intValue());
                task.setTotalNewCount(((Number) stats.getOrDefault("totalNewCount", 0)).intValue());
                task.setTotalUpdateCount(((Number) stats.getOrDefault("totalUpdateCount", 0)).intValue());
                task.setLastExecuteTime(LocalDateTime.now());
                task.setUpdateTime(LocalDateTime.now());

                grabTaskMapper.updateById(task);
            }
        } catch (Exception e) {
            log.error("更新任务统计信息失败: {}", taskId, e);
        }
    }

    /**
     * 获取随机延迟时间（毫秒）
     * 基础延迟 2-5 秒，加上随机波动
     */
    private long getRandomDelay() {
        // 基础延迟 2000-5000ms
        long baseDelay = 2000 + random.nextInt(3000);
        // 添加随机波动 ±500ms
        long randomVariation = random.nextInt(1000) - 500;
        return Math.max(1000, baseDelay + randomVariation); // 最少延迟1秒
    }

    /**
     * 立即执行（异步，使用单线程执行器）
     * @param id 任务ID
     */
    @Override
    public void executeScheduledTaskNow(Long id) {
        taskExecutor.submit(() -> {
            try {
                executeGrabTaskNow(id);
            } catch (Exception e) {
                log.error("执行抓取任务失败, 任务ID: {}", id, e);
            }
        });
    }

    /**
     * 优雅关闭执行器
     */
    @javax.annotation.PreDestroy
    public void shutdown() {
        log.info("正在关闭抓取任务执行器...");
        taskExecutor.shutdown();
        try {
            if (!taskExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
                log.warn("执行器未能在30秒内正常关闭，强制关闭");
                taskExecutor.shutdownNow();
            }
        } catch (InterruptedException e) {
            log.warn("等待执行器关闭时被中断");
            taskExecutor.shutdownNow();
            Thread.currentThread().interrupt();
        }
        log.info("抓取任务执行器已关闭");
    }
}
